package com.liwenfeng;

import java.lang.invoke.*;
import java.util.function.BinaryOperator;

//-Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles
//可以生成lambda函数对象的类
public class LambdaTest {
    public static void main(String[] args) throws Throwable {
//        BinaryOperator<Integer> lambda = (a, b) -> a + b;

/*
        for (Method method : LambdaTest.class.getDeclaredMethods()) {
            System.out.println(method);
        }
*/

/*
        //Methodhandle
        //反射方法调用静态方法
        MethodHandle mh1 = MethodHandles.lookup().findStatic(LambdaTest.class, "lambda$main$2",
                MethodType.methodType(Integer.class, Integer.class, Integer.class));
        System.out.println(mh1.invoke(3, 8));

        //反射方法调用非静态方法
        MethodHandle mh2 = MethodHandles.lookup().findVirtual(MyLambda.class, "apply",
                MethodType.methodType(Integer.class, Integer.class, Integer.class));
        System.out.println(mh2.invoke(new MyLambda(), 4, 9));

        //反射方法调用构造器
        MethodHandle mh3 = MethodHandles.lookup().findConstructor(LambdaTest.class,
                MethodType.methodType(void.class));
        System.out.println(mh3.invoke()); //相当于new LambdaTest()
*/
        //函数对象生成原理
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle impl = lookup.findStatic(LambdaTest.class, "lambda$main$2",
                MethodType.methodType(Integer.class, Integer.class, Integer.class));
        //内部：生成函数对象所需的类 ASM
        CallSite cs = LambdaMetafactory.metafactory(
                lookup,                                                         //lookup对象
                "apply",                                                        //接口方法名
                MethodType.methodType(BinaryOperator.class),                    //创建函数对象的工厂方法长相
                MethodType.methodType(Object.class, Object.class, Object.class),  //接口方法长相
                impl,                                                           //实现方法（lambda$main$2）
                MethodType.methodType(Integer.class, Integer.class, Integer.class)//函数对象实际长相
        );
        //BinaryOperator factory() {return new MyLambda()}
        MethodHandle mh = cs.getTarget(); //函数对象的工厂方法
        BinaryOperator<Integer> invoke = (BinaryOperator<Integer>) mh.invoke();//生成函数对象
        System.out.println(invoke.apply(3, 9));

    }

    static final class MyLambda implements BinaryOperator<Integer> {
        private MyLambda() {
        }

        @Override
        public Integer apply(Integer a, Integer b) {
            return lambda$main$2(a, b);
        }
    }

    private static Integer lambda$main$2(Integer a, Integer b) {
        return a + b;
    }

}
